﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Eventos;

namespace PConexion
{
    public abstract class Conexion
    {
        public Socket SocketConexion;
        public string IPServidorNotificacion { get; set; }
        public string NombreNotificacion { get; set; }

        public abstract bool AbrirConexion(string ip, int puerto);

        /* Metodo que cierra la conexion.
         * Retorno:
         *  false - No se pudo cerrar la conexion.
         *  true - Se pudo cerrar exitosamente la conexion.
         *  */
        public virtual bool CerrarConexion()
        {
            bool retorno = false;
            try
            {
                if (this.SocketConexion != null)
                {
                    //this.SocketConexion.Shutdown(SocketShutdown.Both);//Deshabilitamos el envio y recibo de informacion
                    this.SocketConexion.Disconnect(retorno);
                    this.SocketConexion.Close();
                    retorno = true;
                }
                else
                {
                    Console.WriteLine("Conexion.CerrarConexion: Se intentó cerrar la conexión y ésta no estaba abierta y/o inicializada.");
                    retorno = false;

                }

            }
            catch (SocketException ex)
            {
                Console.WriteLine("Conexion.CerrarConexion: Error al intentar cerrar la conexion.");
                retorno = false;
            }
            return retorno;
        }

        /* Envio de datos a traves de la conexion establecida.
         * Retorno:
         *  >=0 - Se recibieron 0 o más datos.
         *  -1 - Hubo algún error en la recepción de los archivos.
         *  */
        public virtual int EnviarDatos(byte[] buffer)
        {
            int retorno = 0;
            if (this.SocketConexion != null)
            {
                try
                {

                    retorno = this.SocketConexion.Send(buffer);

                }
                catch (SocketException ex)
                {
                    Console.WriteLine("Conexion.EnviarDatos: Error al intentar enviar datos.");
                    retorno = -1;
                }

            }
            else
            {
                Console.WriteLine("Conexion.EnviarDatos: No se pudo enviar datos ya que la conexón no está inicializada.");
                retorno = -1;
            }
            return retorno;
        }

        /* Metodo que recibe datos a través de la conexión.
        * 
        * Retorno:
        *  >=0 - Se recibieron 0 o más bytes.
        *  -1 - Hubo un error en la recepción de bytes.
        *  
        */
        public virtual int RecibirDatos(ref byte[] buffer)
        {

            int bytes_recibidos = 0;
            try
            {
                bytes_recibidos = this.SocketConexion.Receive(buffer, 0, 10008, System.Net.Sockets.SocketFlags.None);
                
                StringBuilder largo = new StringBuilder();
                for (int i = 5; i < 9; i++)
                {
                    largo.Append(Convert.ToChar(buffer[i]).ToString());
                }
                int largoInt = 0;

                int.TryParse(largo.ToString(), out largoInt);

                int RestanBytes = largoInt + 9 - bytes_recibidos;

                int posicion = bytes_recibidos - 1;

                //Si restan Bytes por recibir aun,
                //seguimos obteniendo informacion hasta culminar.

                //Console.WriteLine("Trama Largo: " + largoInt.ToString() + ", RestanBytes: " + RestanBytes.ToString() + ", posicion: " + posicion.ToString());
                while (RestanBytes > 0)
                {
                    //Console.WriteLine("Trama Largo: " + largoInt.ToString() + ", RestanBytes: " + RestanBytes.ToString() + ", posicion: " + posicion.ToString());
                    int bytes_recibidos_temp = 0;
                    byte[] buffer_temp = new byte[10008];
                    bytes_recibidos_temp = this.SocketConexion.Receive(buffer_temp, 0, RestanBytes, System.Net.Sockets.SocketFlags.None);
                    if (bytes_recibidos_temp != 0)
                    {
                        if (bytes_recibidos_temp >= RestanBytes)
                        {
                            for (int i = 0; i < RestanBytes; i++)
                            {
                                buffer[posicion] = buffer_temp[i];
                                posicion++;
                                //Console.WriteLine("RestanBytes: " + RestanBytes.ToString() + ", bytes_recibidos_temp: " + bytes_recibidos_temp.ToString() + ", posicion: " + posicion.ToString() + ", i: " + i.ToString());
                                
                            }
                        }
                        else
                        {
                            for (int i = 0; i < bytes_recibidos_temp; i++)
                            {
                                buffer[posicion] = buffer_temp[i];
                                posicion++;
                                //Console.WriteLine("RestanBytes: " + RestanBytes.ToString() + ", bytes_recibidos_temp: " + bytes_recibidos_temp.ToString() + ", posicion: " + posicion.ToString() + ", i: " + i.ToString());
                                

                            }
                        }
                    }


                    RestanBytes = RestanBytes - bytes_recibidos_temp;
                }
                //if (RestanBytes < 0)
                //{
                //    Console.WriteLine("Lei mucho!");
                //    Console.WriteLine("Trama Largo: " + largoInt.ToString() + ", RestanBytes: " + RestanBytes.ToString() + ", posicion: " + posicion.ToString());
                //    Console.ReadKey();
                //}
            }
            catch (SocketException ex)
            {
                Console.WriteLine("Conexion.RecibirDatos: Se detectó un error al recibir datos en la conexión.");
                bytes_recibidos = -1;
            }
            return bytes_recibidos;
        }

        public bool ConexionActiva()
        {
            return (SocketConexion != null && SocketConexion.Connected);
        }

        public abstract void RegistrarConexionEnServidor(Evento evento);
    }
}
